#ifndef LRU_CACHE_HPP
#define LRU_CACHE_HPP

#include <mutex>
#include <unordered_map>

#include "../CachePolicyIface.h"
#include "./LruNode.hpp"

namespace CachePool
{
    // 约定最少访问在头部
    // 操作两种结构：1.双向循环链表 2.哈希表
    template <typename Key, typename Value>
    class LruCache : public CachePolicyIface<Key, Value>
    {
    public:
        using LruNodeType = LruNode<Key, Value>;
        using NodePtr = std::shared_ptr<LruNodeType>;
        using NodeMap = std::unordered_map<Key, NodePtr>;

        explicit LruCache(const size_t capacity)
            : capacity_(capacity)
        {
            this->initNodeList();
        }

        ~LruCache() override = default;

        // 添加缓存
        void set(const Key &key, const Value &value) override
        {
            if (this->capacity_ <= 0)
            {
                return;
            }

            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->nodeMap_.find(key);
            if (it == this->nodeMap_.end())
            {
                this->addNode(key, value);
                return;
            }

            // 如果在当前容器中，则更新value，并调用get方法->移动链表节点，代表该数据刚被访问
            this->modNode(it->second, value);
        }

        bool get(const Key &key, Value &value) override
        {
            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->nodeMap_.find(key);
            if (it == this->nodeMap_.end())
            {
                return false;
            }

            this->moveMruNode(it->second);
            value = it->second->getValue();
            return true;
        }

        Value get(const Key &key) override
        {
            Value value{};
            // memset(&value, 0, sizeof(value));
            // memset 是按字节设置内存的，对于复杂类型（如 string）使用 memset 可能会破坏对象的内部结构
            this->get(key, value); // 未用返回值
            return value;
        }

        // 删除指定元素，简单测试不一定用得到该方法 × 在LruKCache用到
        void del(const Key &key)
        {
            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->nodeMap_.find(key);
            if (it == nodeMap_.end())
            {
                return;
            }

            this->delListNode(it->second);
            this->nodeMap_.erase(it);
        }

    private:
        void initNodeList()
        {
            // 创建首尾虚拟节点
            dummyHead_ = std::make_shared<LruNodeType>(Key{}, Value{});
            dummyTail_ = std::make_shared<LruNodeType>(Key{}, Value{});
            dummyHead_->next_ = dummyTail_;
            dummyTail_->prev_ = dummyHead_;
        }

        void addNode(const Key &key, const Value &value)
        {
            if (this->nodeMap_.size() >= this->capacity_)
            {
                this->evictLruNode();
            }

            NodePtr newNode = std::make_shared<LruNodeType>(key, value);
            this->addListNode(newNode);
            this->nodeMap_[key] = newNode;
        }

        // 驱逐最近最少访问
        void evictLruNode()
        {
            NodePtr lruNode = this->dummyHead_->next_;
            // if (lruNode == this->mainDummyTail_)
            // {
            //     return;
            // }

            this->delListNode(lruNode);
            this->nodeMap_.erase(lruNode->getKey());
        }

        void delListNode(NodePtr node)
        {
            node->prev_->next_ = node->next_;
            node->next_->prev_ = node->prev_;
        }

        // 从尾部插入结点
        void addListNode(NodePtr node)
        {
            node->prev_ = this->dummyTail_->prev_;
            node->next_ = this->dummyTail_;

            this->dummyTail_->prev_->next_ = node; // 这里不能改顺序
            this->dummyTail_->prev_ = node;
        }

        void modNode(NodePtr node, const Value &value)
        {
            node->setValue(value);
            this->moveMruNode(node); // M：most
        }

        // 将该节点移动到最新的位置
        void moveMruNode(NodePtr node)
        {
            this->delListNode(node);
            this->addListNode(node);
        }

    private:
        size_t capacity_;   // 缓存容量
        NodePtr dummyHead_; // 虚拟头结点
        NodePtr dummyTail_;
        NodeMap nodeMap_; // key -> Node

        std::mutex mutex_;
    };
} // namespace CachePool

#endif // LRU_CACHE_HPP